package com.andy.network.base


import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.andy.network.entity.ApiFailedResponse
import com.andy.network.entity.ApiErrorResponse
import com.andy.network.entity.ApiResponse
import com.andy.network.entity.ApiSuccessResponse
import com.andy.network.livedata.EventLiveData
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch


/**
 * 作者　: hegaojian
 * 时间　: 2019/12/12
 * 描述　: ViewModel的基类 使用ViewModel类，放弃AndroidViewModel，原因：用处不大 完全有其他方式获取Application上下文
 */
open class BaseViewModel : ViewModel() {

    //页面状态
    val viewStateValue by lazy { EventLiveData<PageViewState>() }

    val dialogLoadingValue by lazy { EventLiveData<Boolean>() }

    val loadingValue: UiStateChange by lazy { UiStateChange() }

    fun <T> makeViewHttp(resultFlow: MutableStateFlow<ApiResponse<T>>, block: suspend () -> ApiResponse<T>) {
        viewModelScope.launch {
            flow {
                emit(executeViewHttp { block() })
            }.collect { result ->
                resultFlow.value = result
            }
        }
    }

    fun <T> makeDialogHttp(resultFlow: MutableStateFlow<ApiResponse<T>>, block: suspend () -> ApiResponse<T>) {
        viewModelScope.launch {
            flow {
                emit(executeDialogHttp { block() })
            }.collect { result ->
                resultFlow.value = result
            }
        }
    }

    private suspend fun <T> executeViewHttp(block: suspend () -> ApiResponse<T>): ApiResponse<T> {
        runCatching {
            viewStateValue.postValue(PageViewState.ShowLoading)
            block()
        }.onSuccess {
            dialogLoadingValue.postValue(false)
            return parseResponse(it)
        }.onFailure {
            viewStateValue.postValue(PageViewState.ShowError)
            return ApiFailedResponse(it)
        }
        viewStateValue.postValue(PageViewState.ShowError)
        return ApiFailedResponse(Throwable("未知错误"))
    }

    private suspend fun <T> executeDialogHttp(block: suspend () -> ApiResponse<T>): ApiResponse<T> {
        runCatching {
            dialogLoadingValue.postValue(true)
            block()
        }.onSuccess {
            dialogLoadingValue.postValue(false)
            return parseResponse(it)
        }.onFailure {
            dialogLoadingValue.postValue(false)
            return ApiFailedResponse(it)
        }
        return ApiFailedResponse(Throwable("未知错误"))
    }

    private fun <T> parseResponse(response: ApiResponse<T>): ApiResponse<T> {
        if (response.isSuccess) {
            val data = response.content
            data?.let { bean ->
                viewStateValue.postValue(PageViewState.ShowContent)
                return ApiSuccessResponse(bean)
            } ?: let {
                viewStateValue.postValue(PageViewState.ShowError)
                return ApiFailedResponse(Throwable("content is null"))
            }
        } else {
            viewStateValue.postValue(PageViewState.ShowError)
            return ApiErrorResponse(response.errorCode, response.errorMsg)
        }
    }

    /**
     * 内置封装好的可通知Activity/fragment 显示隐藏加载框 因为需要跟网络请求显示隐藏loading配套才加的，不然我加他个鸡儿加
     */
    inner class UiStateChange {

        //显示加载框
        val showDialog by lazy { EventLiveData<String>() }

        //隐藏
        val dismissDialog by lazy { EventLiveData<Boolean>() }
    }
}

sealed class PageViewState {
    object ShowLoading : PageViewState()
    object ShowContent : PageViewState()
    object ShowEmpty : PageViewState()
    object ShowError : PageViewState()
}
